package stores

import (
	"jvm/instructions/base"
	"jvm/rtda"
	"jvm/rtda/heap"
	. "jvm/typedef"
)

// **************************************************
// 检查空指针
func checkNotNil(ref *heap.Object) {
	if ref == nil {
		panic("java.lang.NullPointerException")
	}
}

// 检查下标是否越界
func checkIndex(arrLen I4, index I4) {
	if index < 0 || index >= arrLen {
		panic("ArrayIndexOutOfBoundsException")
	}
}

// **************************************************
type AASTORE struct{ base.NoOperandsInst }

func (self *AASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopRef()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	refs := arrRef.Refs()
	checkIndex(I4(len(refs)), index)
	refs[index] = val
}

// **************************************************
type BASTORE struct{ base.NoOperandsInst }

func (self *BASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopInt()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	bytes := arrRef.Bytes()
	checkIndex(I4(len(bytes)), index)
	bytes[index] = I1(val)
}

// **************************************************
type CASTORE struct{ base.NoOperandsInst }

func (self *CASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopInt()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	chars := arrRef.Chars()
	checkIndex(I4(len(chars)), index)
	chars[index] = U2(val)
}

// **************************************************
type SASTORE struct{ base.NoOperandsInst }

func (self *SASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopInt()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	shorts := arrRef.Shorts()
	checkIndex(I4(len(shorts)), index)
	shorts[index] = I2(val)
}

// **************************************************

type IASTORE struct{ base.NoOperandsInst }

func (self *IASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopInt()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	ints := arrRef.Ints()
	checkIndex(I4(len(ints)), index)
	ints[index] = val
}

// **************************************************
type LASTORE struct{ base.NoOperandsInst }

func (self *LASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopLong()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	longs := arrRef.Longs()
	checkIndex(I4(len(longs)), index)
	longs[index] = val
}

// **************************************************
type FASTORE struct{ base.NoOperandsInst }

func (self *FASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopFloat()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	floats := arrRef.Floats()
	checkIndex(I4(len(floats)), index)
	floats[index] = val
}

// **************************************************
type DASTORE struct{ base.NoOperandsInst }

func (self *DASTORE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopDouble()
	index := stack.PopInt()
	arrRef := stack.PopRef()
	checkNotNil(arrRef)

	doubles := arrRef.Doubles()
	checkIndex(I4(len(doubles)), index)
	doubles[index] = val
}

// **************************************************
